package crypto

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"encoding/binary"
	"encoding/gob"
	"fmt"
)

func AESEncryptInt64(val int64, key, nonce []byte) ([]byte, error) {
	var buf = make([]byte, 8)
	binary.BigEndian.PutUint64(buf, uint64(val))
	data, err := AESEncrypt(buf, key, nonce)
	if err != nil {
		return nil, fmt.Errorf("aes encrypt error: %w", err)
	}
	return data, nil
}

func AESDecryptInt64(buf []byte, key, nonce []byte) (int64, error) {
	data, err := AESDecrypt(buf, key, nonce)
	if err != nil {
		return 0, fmt.Errorf("aes decrypt error: %w", err)
	}
	return int64(binary.BigEndian.Uint64(data)), nil
}

func AESEncryptString(val string, key, nonce []byte) ([]byte, error) {
	data, err := AESEncrypt([]byte(val), key, nonce)
	if err != nil {
		return nil, fmt.Errorf("aes encrypt error: %w", err)
	}
	return data, nil
}

func AESDecryptString(buf []byte, key, nonce []byte) (string, error) {
	data, err := AESDecrypt(buf, key, nonce)
	if err != nil {
		return "", fmt.Errorf("aes decrypt error: %w", err)
	}
	return string(data), nil
}

// AESEncyptObject 加密对象
func AESEncyptObject(obj interface{}, key, nonce []byte) ([]byte, error) {
	var buf bytes.Buffer
	encoder := gob.NewEncoder(&buf)
	if err := encoder.Encode(obj); err != nil {
		return nil, fmt.Errorf("gob encode error: %w", err)
	}

	data, err := AESEncrypt(buf.Bytes(), key, nonce)
	if err != nil {
		return nil, fmt.Errorf("aes encypt error: %w", err)
	}
	return data, nil
}

// AESDecryptObject 解密对象
func AESDecryptObject(data []byte, key, nonce []byte, obj interface{}) error {
	res, err := AESDecrypt(data, key, nonce)
	if err != nil {
		return fmt.Errorf("aes decypt error: %w", err)
	}
	// var tk Token
	decoder := gob.NewDecoder(bytes.NewBuffer(res))
	if err := decoder.Decode(obj); err != nil {
		return fmt.Errorf("gob decode error: %w", err)
	}
	return nil
}

// AESEncrypt AES 加密
func AESEncrypt(src, key, nonce []byte) ([]byte, error) {
	// The key argument should be the AES key, either 16 or 32 bytes
	// to select AES-128 or AES-256.
	//key := []byte(k)
	plaintext := src //[]byte(src)

	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	//nonce, _ := hex.DecodeString(n)

	aesGcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}
	// aesGcm.Seal()
	cipherText := aesGcm.Seal(nil, nonce, plaintext, nil)

	return cipherText, nil
}

// AESDecrypt AES 解密
func AESDecrypt(src, key, nonce []byte) ([]byte, error) {
	// The key argument should be the AES key, either 16 or 32 bytes
	// to select AES-128 or AES-256.
	//key := []byte(k)
	//cipherText, _ := hex.DecodeString(src)
	//cipherText := src
	//nonce, _ := hex.DecodeString(n)
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	aesGcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	plainText, err := aesGcm.Open(nil, nonce, src, nil)
	if err != nil {
		return nil, err
	}

	return plainText, nil
}
